﻿using System;
using System.Text.RegularExpressions;
using System.Web;
using log4net;

// web.config registration example
// <add name="GateKeeper" type="GateKeeper.GateKeeperModule"/>

namespace GateKeeper
{
    public class GateKeeperModule : IHttpModule
    {
        public static readonly log4net.ILog log = log4net.LogManager.GetLogger("Global.asax");
        public static Settings config = new Settings();

        #region IHttpModule Members
        public GateKeeperModule()
        { }
        public void Dispose()
        { }
        public void Init(HttpApplication application)
        { 
            application.BeginRequest += new EventHandler(application_BeginRequest);
            application.EndRequest += new EventHandler(application_EndRequest);

            // Set logfile name and application name variables
            log4net.GlobalContext.Properties["LogName"] = GetType().Assembly.GetName().Name + ".log";
            log4net.GlobalContext.Properties["ApplicationName"] = GetType().Assembly.GetName().Name;

            // Load log4net configuration
            System.IO.FileInfo logfile = new System.IO.FileInfo(HttpContext.Current.Server.MapPath("log4net.config"));
            log4net.Config.XmlConfigurator.ConfigureAndWatch(logfile);

            // Record application startup
            log.Debug("GateKeeper initialized");
        
        }
        #endregion // IHttpModule Members

        protected void application_BeginRequest(object sender, EventArgs e)
        {
            HttpContext current = HttpContext.Current;
            HttpRequest request = HttpContext.Current.Request;

            // execute trace entries
            Utils.Begin_NewRequest(current);

            // load configuration settings from config file
            config.Load();

            // execute any eventhandler entries
            onBeginRequest(current, config);

            // Check if GK is enabled
            if (!config.EnableGateKeeper)
            {
                log.Debug("GateKeeper disabled in config settings");
                return; 
            }

            // Checking if UserAgent is empty and if GK should block empty UserAgents
            if ( string.IsNullOrEmpty(request.UserAgent) && config.DenyEmptyUserAgent)
            { AccessDenied.Display(current, Violation.EmptyUserAgent); }

            // Load whitelist data
            Utils.xmlWhiteList = Utils.GetXMLDocument(XmlFileType.WhiteList);
            
            //TODO: Need to change this to load the IPList instead of the XML file
            // Load blacklist data
            Utils.xmlBlackList = Utils.GetXMLDocument(XmlFileType.BlackList);

            // Load honeypot data
            Utils.xmlHoneyPotList = Utils.GetXMLDocument(XmlFileType.HoneyPotList);

            // Check if request matches a whitelist
            if (Whitelist.isWhiteListRequest(current))
            {
                log.Debug("Request passed WhiteList check - let them pass");
                return;
            }

            // Check if IPAddress matches blacklist
            if (CheckIPAddress.IPEntryExists(Utils.xmlBlackList, request.UserHostAddress))
            { AccessDenied.Display(current, Violation.IPAddress); }

            // Check if UserAgent matches blacklist
            if (!string.IsNullOrEmpty(request.UserAgent) && Utils.UserAgentExists(Utils.xmlBlackList, request.UserAgent))
            { AccessDenied.Display(current, Violation.UserAgent); }

            // Check IP Address against HttpBL
            if (HttpBLLookup.isHttpBLSuspect(current))
            { AccessDenied.Display(current, Violation.HttpBL); }

            // Check IP Address against DroneBL
            if (DroneBLLookup.isDroneBLSuspect(current))
            { AccessDenied.Display(current, Violation.DroneBL); }

            // Check if IP is an Open Proxy
            if (ProxyBLLookup.isProxyBLSuspect(current))
            { AccessDenied.Display(current, Violation.ProxyBL); }

            // Check if request is hotlinked
            if (config.BlockHotLinking && Hotlink.isHotlinked(current))
            { AccessDenied.Display(current, Violation.Hotlink); }

            // Check if request is a honeypot violator
            if (config.EnableHoneyPot && Honeypot.isHoneyPotVoilator(current))
            { AccessDenied.Display(current, Violation.HoneyPot); }

            // Check if request is for virtual honeypot stats url
            if (config.EnableHoneyPotStats && 
                !string.IsNullOrEmpty(config.HoneyPotStatsPath) &&
                    Regex.IsMatch(request.Url.AbsolutePath, config.HoneyPotStatsPath, RegexOptions.IgnoreCase))
            { HoneyPotStats.Display(); }

            // Request passed all checks - let them pass
        }

        protected void application_EndRequest(object sender, EventArgs e)
        {
            onEndRequest(HttpContext.Current, config);
            Utils.End_NewRequest(HttpContext.Current);
        }

        #region Event Handler Methods
        public static event EventHandler<EventArgs> BeginRequest;
        private static void onBeginRequest(HttpContext current, Settings config)
        {
            if (BeginRequest != null)
            {
                log.Debug("Executing BeginRequest eventHandler");
                BeginRequest(current, new EventArgs()); 
            }
        }

        public static event EventHandler<EventArgs> EndRequest;
        private static void onEndRequest(HttpContext current, Settings config)
        {
            if (EndRequest != null)
            {
                log.Debug("Executing EndRequest eventHandler");
                EndRequest(current, new EventArgs()); 
            }
        }
        #endregion // Event Handler Methods

    }
}